home *** CD-ROM | disk | FTP | other *** search
- ;
- ; This file provides the lowlevel interface needed for creating a DOS
- ; device driver. This module is designed to be assembled using Borlands
- ; TASM. All you need to do is modify the C module _handler to suit your
- ; needs and then link everything together.
- ;
- ; As usual you may use these modules as you please without paying me anything
- ; unless of course you want to pay me, I could always use another trip to the
- ; Bahamas. If you would like to ask me anything just send E-Mail to
- ; 76207,674
-
- DONE equ 0100h ; operation complete bit
-
- .model small ; memory models must match between all modules
- .286 ; you could change this to what ever you wish
- .code ; simplified segment directives make segments
- ; match C segment directives
- extrn _handler:near ; external C module
-
- org 0 ; all device drivers start at location 0
- ;
- ; the following header is required in all device drivers
- ;
- header dd -1 ; pointer to next driver in the chain
- attribute dw 8000h ; character device
- dw offset strategy ; offset to stratgey routine
- dw offset interrupt ; offset to interrupt routine
- db 'GENERIC$' ; driver name 8 bytes padded
- ;
- ; end of header
- ;
-
- ;
- ; local data
- ;
- request_header dd ? ; address of DOS request header
- oldss dw ? ; old stack segment
- oldsp dw ? ; old stack pointer
-
- local_stack db 128 dup ('stack ') ; 1k local stack
- tos dw ? ; top of stack
-
- ;
- ; The strategy routine just stores the address of the request header.
- ; When DOS calls the device driver it first calls the strategy routine
- ;
- strategy proc far
- mov word ptr cs:[request_header],bx
- mov word ptr cs:[request_header+2],es
- ret
- strategy endp
-
- ;
- ; DOS calls the interrupt routine after the stratgey routine returns
- ;
- interrupt proc far
- pushf ; we need to save the state of the machine
- push ax ; since we're being called from the kernel
- push bx
- push cx
- push dx
- push ds
- push es
- push si
- push di
- push bp
-
- ;
- ; we establish our own data segment and make it equal to the code segment
- ; since our local data is located in code segment
- ;
- push cs
- pop ds
- ;
- ; Load es:bx with the address of the request header, DOS passes information
- ; to the device driver through the request header
- ;
- les bx,[request_header]
-
- ;
- ; Now we save the current stack and setup our own stack incase the calling
- ; program doesn't have enough stack space available for the driver
- ;
- mov word ptr oldss,ss ; save stack segment
- mov word ptr oldsp,sp ; save stack pointer
- mov ax,cs ; get our stack segment
- mov ss,ax ; establish stack
- mov sp,offset tos - 2 ; and pointer
-
- ; Now push the request header address on the stack and and call the
- ; C routine using the TASM language independent calling feature
- ; Just call the routine specifing the language followed by the parms
- ; TASM will push the parms on the stack in the correct order and adjust
- ; the stack when the routine returns
- ;
- call _handler C,BX,ES
- ;
- ; Note: on 80x86 machines segment:offset memory variables are referenced in
- ; reverse order so the variable addressed by es:bx is stored in memory with
- ; bx in the first word and es in the second word. In the above call bx is
- ; before es because we pass variables to C functions on the stack which is
- ; just physical memory referenced by SS and SP
- ;
- ; AX contains status code returned from _handler which is declare as
- ; int handler(RequestHeader far *) in the C file
- ;
- ; Now that we are back we must restore the original stack and finish
- ; processing the driver code
- ;
- push cs ; let's restore our data segment since it got
- pop ds ; changed in the C module
-
- mov ss,word ptr oldss ; restore original stack seg
- mov sp,word ptr oldsp ; and stack pointer
-
- ;
- ; The remaining code restores the machine state and then returns telling
- ; DOS that the operation is complete
- ;
- finish: les bx,[request_header] ; get address of request header
- or ax,DONE ; set completion bit
- mov es:[bx]+3,ax ; store it in the request header
- pop bp ; restore all registers
- pop di
- pop si
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- ret ; and return to DOS, this is not a real interrupt
- ; routine so we don't need an IRET
- interrupt endp
-
- end